//////////////////////////////////////////////////////////////////////////
//
// NO_Singleton.h
//
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
#ifndef NO_SINGLETON_H
#define NO_SINGLETON_H

//////////////////////////////////////////////////////////////////////////
#include "../thread/NO_Lock.h"
#include "../utils/NO_StdDefs.h"

//////////////////////////////////////////////////////////////////////////
// Gamma Singleton creation policy
//////////////////////////////////////////////////////////////////////////
struct NO_Gamma 
{
	template <class SingleClass>
	static SingleClass* create(const volatile SingleClass* object = 0)
	{return new SingleClass;}
	
	template <class SingleClass>
	static void destroy(SingleClass* object)
    {delete object;}
};

//////////////////////////////////////////////////////////////////////////
// Meyers Singleton creation policy
//////////////////////////////////////////////////////////////////////////
struct NO_Meyers 
{
	template <class SingleClass>
	static SingleClass* create(const volatile SingleClass* object = 0) 
	{
		static SingleClass _instance;
		return &_instance;
	}

	template <class SingleClass>
	static void destroy(SingleClass* object)
    {}
};

//////////////////////////////////////////////////////////////////////////
// Singleton class template
//////////////////////////////////////////////////////////////////////////
template <class Type, class Policy=NO_Meyers, class Lock=NO_Lock>
class NO_Singleton
{
public:
	//////////////////////////////////////////////////////////////////////////
	typedef Type	value_type;
	typedef Type*	pointer; 
	typedef Type&	reference; 

	//////////////////////////////////////////////////////////////////////////
	static reference instance(void) 
	{
		if(object)	{return *object;}

		lock.writeLock();
		object = Policy::create(object);
		if (!object) 
		{
			lock.unlock();
			return *object;
		}
		lock.unlock();
		return *object;
	}
		
	//////////////////////////////////////////////////////////////////////////
	static void destroy(void) 
	{
		lock.writeLock();
		if (object) {Policy::destroy(object);object=0;}
		lock.unlock();
	}
	
private:
	//////////////////////////////////////////////////////////////////////////
	NO_Singleton(); 
	~NO_Singleton(); 
	NO_Singleton(NO_Singleton const&); 
	NO_Singleton& operator=(NO_Singleton const&); 
	static pointer object;
	static Lock lock;
	static bool initialized;
};

//////////////////////////////////////////////////////////////////////////
template <class SingleClass, class Policy, class Lock>
SingleClass* NO_Singleton<SingleClass,Policy,Lock>::object=0;

//////////////////////////////////////////////////////////////////////////
template <class SingleClass, class Policy, class Lock>
bool NO_Singleton<SingleClass,Policy,Lock>::initialized=NO_Singleton<SingleClass,Policy,Lock>::init();

//////////////////////////////////////////////////////////////////////////
template <class SingleClass, class Policy, class Lock>
Lock NO_Singleton<SingleClass,Policy,Lock>::lock = Lock();

#endif 
